using System.Collections;
using Curriculum.Business.Clases;
using Curriculum.Business.LectorMetadatos;
using Antecedente = Curriculum.Business.LectorMetadatos.Antecedente;
using Atributo = Curriculum.Business.LectorMetadatos.Atributo;
using XML = Curriculum.Business.LectorMetadatos;

namespace Curriculum.Business.Manejadores
{
	public struct ParIdRaizHoja
	{
		public string idAntecedenteRaiz;
		public string idAntecedenteHoja;
	}
	/// <summary>
	/// Summary description for ManejadorAntecedentes.
	/// </summary>
	public class ManejadorAntecedentes
	{
		private string _idVersion;
		private static ManejadorAntecedentes instancia = null;
		private ListaAntecedentesXML listaAntecedentesXML;
		private Clases.Antecedente estructura;

		public static ManejadorAntecedentes GetInstancia(string idVersion)
		{
			if (instancia == null)
				instancia = new ManejadorAntecedentes(idVersion);
			
			return instancia;
		}

		public static ManejadorAntecedentes GetInstancia()
		{
			return instancia;
		}
		public void Reset()
		{
			instancia = null;
		}
		private ManejadorAntecedentes(string idVersion)
		{
			this._idVersion = idVersion;
			LectorAntecedentes lectorAntecedentes = new LectorAntecedentes();
			listaAntecedentesXML = lectorAntecedentes.Leer(idVersion);
			this.construirEstructura();
		}
	
		private void construirEstructura()
		{
			estructura = new Clases.Antecedente();
			ArrayList aListAntecedentes = new ArrayList();

			if ((listaAntecedentesXML != null) && (listaAntecedentesXML.antecedentes != null))
			{
				foreach (Antecedente antecedenteXML in listaAntecedentesXML.antecedentes)
				{
					aListAntecedentes.Add(this.construirAntecedente(antecedenteXML, null));
				}
			}
		
			estructura.Antecedentes = new Clases.Antecedente[aListAntecedentes.Count];
			aListAntecedentes.CopyTo(estructura.Antecedentes);
		}

		private Clases.Antecedente construirAntecedente(Antecedente antecedenteXML, string idPadre)
		{	
			Clases.Antecedente antecedente = new Clases.Antecedente();

			antecedente.IdAntecente = antecedenteXML.idAntecedente;
			antecedente.Nombre = antecedenteXML.nombre;
			antecedente.EsAgregacion = antecedenteXML.agregacion;
			antecedente.IdPadre = idPadre;
			antecedente.Atributos = this.ConstruirAtributos(antecedenteXML.atributos);
			
			if (antecedenteXML.antecedentesXML != null)
			{
				ArrayList antecedentesList = new ArrayList();
				foreach (Antecedente antecedenteXMLHijo in antecedenteXML.antecedentesXML.antecedentes)
				{
					antecedentesList.Add(this.construirAntecedente(antecedenteXMLHijo, antecedente.IdAntecente));
				}
				antecedente.Antecedentes = new Clases.Antecedente[antecedentesList.Count];
				antecedentesList.CopyTo(antecedente.Antecedentes);
			}
	
			return antecedente;
		}

		private Clases.Atributo[] ConstruirAtributos(ListaAtributoAntecedente atributosXML)
		{
			if ((atributosXML != null) && (atributosXML.atributos != null))
			{
				AtributoBuilder atributoBuilder;
				ArrayList aListAtributos = new ArrayList();
				Clases.Atributo[] atributos;

				foreach (atributoAntecedente atributoAntecedenteXML in atributosXML.atributos)
				{
					atributoBuilder = new AtributoBuilder();
					Atributo atributoXML = MasterData.GetInstancia().GetAtributo(atributoAntecedenteXML.idAtributo);
					
					atributoBuilder.SetLongitud(atributoXML.longitud);
					atributoBuilder.SetNombre(atributoXML.nombre);
					atributoBuilder.SetEsOpcional(atributoXML.opcional);
					atributoBuilder.SetIdAtributo(atributoXML.idAtributo);
					atributoBuilder.SetIdTipoDato(atributoXML.tipo);

					aListAtributos.Add(atributoBuilder.GetObjetoCompleto());
				}
				
				atributos = new Clases.Atributo[aListAtributos.Count];
				aListAtributos.CopyTo(atributos);

				return atributos;
			}
			else
			{
				return new Clases.Atributo[0];
			}
		}

		/// <summary>
		/// retorna el antecedente con igual id al recibido
		/// </summary>
		/// <param name="idAntecedente">id del antecedente buscado</param>
		/// <returns></returns>
		public Clases.Antecedente GetAntecedente(string idAntecedente)
		{
			foreach (Clases.Antecedente antecedente in estructura.Antecedentes)
			{
				if (antecedente.IdAntecente.Equals(idAntecedente))
				{
					return antecedente;
				}
				else
				{
					Clases.Antecedente antecedenteBuscado;

					if ((antecedente.Antecedentes != null) && 
						((antecedenteBuscado = this.GetAntecedente(antecedente.Antecedentes, idAntecedente)) != null) )		
						return antecedenteBuscado;
				}
			}
			return null;
		}

		/// <summary>
		/// retorna el antecedente que tenga el id indicado y tenga en la raiz un 
		/// antecedente con el id igual a idAntecedenteRaiz
		/// </summary>
		/// <param name="idAntecedente">id del antecedente buscado</param>
		/// <param name="idAntecedenteRaiz">id de la raiz del antecedente buscado</param>
		/// <returns>Antecedente, null si no lo encuentra</returns>
		public Clases.Antecedente GetAntecedente(string idAntecedente, string idAntecedenteRaiz)
		{
			foreach (Clases.Antecedente antecedente in estructura.Antecedentes)
			{
				if (antecedente.IdAntecente.Equals(idAntecedenteRaiz))
				{
					if (antecedente.IdAntecente.Equals(idAntecedente))
						return antecedente;
					
					Clases.Antecedente antecedenteBuscado;

					if ((antecedente.Antecedentes != null) && 
						((antecedenteBuscado = this.GetAntecedente(antecedente.Antecedentes, idAntecedente)) != null) )		
						return antecedenteBuscado;
				}
			}
			return null;
		}

		// es recursivo sobre todo el arbol
		private Clases.Antecedente GetAntecedente(Clases.Antecedente[] antecedentes, string idAntecedente)
		{
			foreach (Clases.Antecedente antecedente in antecedentes)
			{
				if (antecedente.IdAntecente.Equals(idAntecedente))
				{
					return antecedente;
				}
				else
				{
					Clases.Antecedente antecedenteBuscado;

					if ((antecedente.Antecedentes != null) && 
						((antecedenteBuscado = this.GetAntecedente(antecedente.Antecedentes, idAntecedente)) != null) )		
						return antecedenteBuscado;
				}
			}
			return null;
		}

		public Clases.Antecedente Estructura
		{
			get{ return estructura; }
		}
		
				
		/// <summary>
		/// Con un id de un antecedente hoja y uno de un antecedente raiz, 
		/// te da toda la estructura desde la raiz hasta la hoja
		/// <param name="idAntecedente">id del antecedente hoja</param>
		/// <param name="idAntecedenteRaiz">id del antecedente raiz</param>
		/// <returns>el antecedente buscado, null si no lo encuentra</returns>
		public Clases.Antecedente ObtenerEstructuraAntecedente(string idAntecedente, string idAntecedenteRaiz)
		{
			Clases.Antecedente antecedente;

			if ( (antecedente =(Clases.Antecedente)this.GetAntecedente(idAntecedente, idAntecedenteRaiz).Clone()) != null)
			{
				Clases.Antecedente antecedenteHijo = null;

				while (antecedente.IdPadre != null )
				{
					antecedenteHijo = antecedente;
					idAntecedente = antecedente.IdPadre;
					antecedente = (Clases.Antecedente)this.GetAntecedente(idAntecedente, idAntecedenteRaiz).Clone();
					antecedente.Antecedentes = new Clases.Antecedente[1];
					antecedente.Antecedentes.SetValue(antecedenteHijo, 0);
				}
			}
			return antecedente;
		}		

		public string GetNombreAntecedente(string idAntecedente)
		{
			string nombre;
			try 
			{
				nombre = this.GetAntecedente(idAntecedente).Nombre;
			}
			catch
			{
				nombre = string.Empty;
			}
			return nombre;
		}

		public ICollection GetIdsHojas()
		{
			ArrayList idsHojas = new ArrayList();
			ParIdRaizHoja parIdRaizhoja;
			if (HayAntecedentes())
			{
				foreach (Antecedente antecedente in this.listaAntecedentesXML.antecedentes)
				{
					ListaAntecedentesXML listaAntecedentesXMLHoja = GetAntecedentesHoja(antecedente.idAntecedente);
					foreach (Antecedente antecedenteHoja in listaAntecedentesXMLHoja.antecedentes)
					{
						parIdRaizhoja.idAntecedenteHoja = antecedenteHoja.idAntecedente;
						parIdRaizhoja.idAntecedenteRaiz = antecedente.idAntecedente;
						idsHojas.Add(parIdRaizhoja);
					}
				}
				return idsHojas;
			}
			return null;
		}

		public ListaAntecedentesXML GetAntecedentesHoja(string idAntecedenteRaiz)
		{
			ArrayList aListAntecedentesHoja = new ArrayList();
			if (HayAntecedentes())
			{
				foreach (Antecedente antecedente in this.listaAntecedentesXML.antecedentes)
				{
					if (antecedente.idAntecedente == idAntecedenteRaiz)
					{
						if (antecedente.antecedentesXML == null)
						{
							aListAntecedentesHoja.Add(antecedente);
						}
						else
						{
							aListAntecedentesHoja.AddRange(GetAntecedentesHoja(antecedente.antecedentesXML));
						}
					}
				}
			}
			ListaAntecedentesXML listaAntecedentesXML = new ListaAntecedentesXML();
			listaAntecedentesXML.antecedentes = new Antecedente[aListAntecedentesHoja.Count];
			aListAntecedentesHoja.CopyTo(listaAntecedentesXML.antecedentes);
			
			return listaAntecedentesXML;
		}

		public ICollection GetAntecedentesHoja(ListaAntecedentesXML antecedentesXML)
		{
			ArrayList aListAntecedentes = new ArrayList();
			if (antecedentesXML.antecedentes != null)
			{
				foreach (Antecedente antecedenteHijo in antecedentesXML.antecedentes)
				{
					if (antecedenteHijo.antecedentesXML == null)
					{
						aListAntecedentes.Add((antecedenteHijo));
					}
					else
					{
						aListAntecedentes.AddRange(GetAntecedentesHoja(antecedenteHijo.antecedentesXML));						 
					}
				}
				return aListAntecedentes;
			}
			return null;
		}

		private bool HayAntecedentes()
		{
			return (this.listaAntecedentesXML != null);
		}			
	}
}

